﻿using System;
using System.Data;

namespace EnterpriseFramework.DataAccess
{
    public abstract class AbstractColumn : IEquatable<AbstractColumn>
    {
        private string columnName;
        private string name;
        private DbType dbtype;
        private int size;
        private bool primaryKey;
        private bool autoIncrement;
        private bool concurrency;
        private bool allowNull;
        private bool isComputed;
        private bool isReadOnly;
        private bool isUnique;
        private bool included = true;

        /// <summary>
        /// Used to include this column in result set or not.
        /// </summary>
        public bool Included
        {
            get { return included; }
            set { included = value; }
        }

        /// <summary>
        /// Creates a new column.
        /// </summary>
        /// <param name="name">column name</param>
        /// <param name="dbtype">database data type</param>
        /// <param name="size">size of the database data type</param>
        /// <param name="precision">precision of the database data type</param>
        /// <param name="scale">scale of the database data type</param>
        /// <param name="primaryKey">whether this column is a primary key</param>
        /// <param name="autoIncr">whether this column is an auto generated column</param>
        /// <param name="concurrency">whether this column is used for concurrency checks</param>
        public AbstractColumn(string name, DbType dbtype, int size, bool _allowNull, bool _isComputed, bool _isReadOnly,
                        bool primaryKey, bool autoIncr, bool _isUnique, bool concurrency, string _columnName)
        {
            this.columnName = _columnName;
            this.name = name;
            this.dbtype = dbtype;
            this.size = size;
            this.primaryKey = primaryKey;
            this.autoIncrement = autoIncr;
            this.concurrency = concurrency;
            this.allowNull = _allowNull;
            this.isComputed = _isComputed;
            this.isReadOnly = _isReadOnly;
            this.isUnique = _isUnique;
        }

        /// <summary>
        /// Get or sets Property/Field Name.
        /// </summary>
        public string ColumnName
        {
            get { return columnName; }
        }

        /// <summary>
        /// Get or sets Database column name.
        /// </summary>
        public string Name
        {
            get { return name; }
        }

        /// <summary>
        /// Gets the database data type of this column.
        /// </summary>
        public DbType DBType
        {
            get { return dbtype; }
        }

        /// <summary>
        /// Gets or sets the size of the database data type.
        /// </summary>
        public int Size
        {
            get { return size; }
        }

        /// <summary>
        /// Get or sets the Field Allow Null or not.
        /// </summary>
        public bool AllowNull
        {
            get { return allowNull; }
        }

        /// <summary>
        /// Get or sets if Field is Compueded or not. 
        /// </summary>
        public bool IsComputed
        {
            get { return isComputed; }
        }

        /// <summary>
        /// Get or sets if Field is Read only.
        /// </summary>
        public bool IsReadOnly
        {
            get { return isReadOnly; }
        }

        /// <summary>
        /// Gets or sets whether this column is a primary key column.
        /// </summary>
        public bool PrimaryKey
        {
            get { return primaryKey; }
        }

        /// <summary>
        /// Gets or sets whether this column is an auto incrementing column.
        /// </summary>
        public bool AutoIncrement
        {
            get { return autoIncrement; }
        }

        /// <summary>
        /// Gets or sets whether this column is used for concurrency checks.
        /// </summary>
        public bool Concurrency
        {
            get { return concurrency; }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsUnique
        {
            get { return isUnique; }
        }

        /// <summary>
        /// Checks for equality with another object.
        /// </summary>
        /// <param name="obj">another object</param>
        /// <returns>true if equal, false otherwise</returns>
        public override bool Equals(object obj)
        {
            if (obj is AbstractColumn)
                return Equals((AbstractColumn)obj);
            else
                return false;
        }

        /// <summary>
        /// Checks for equality with another column.
        /// </summary>
        /// <param name="other">another column</param>
        /// <returns>true if equal, false otherwise</returns>
        public bool Equals(AbstractColumn other)
        {
            if (other == null)
                return false;
            return name.Equals(other.name) &&
                dbtype.Equals(other.dbtype) && size.Equals(other.size) &&
                primaryKey.Equals(other.primaryKey) && autoIncrement.Equals(other.autoIncrement);
        }

        /// <summary>
        /// True if this column can be written to. That is,
        /// whether calling the Write method can actually
        /// attempt to write a value into a target object.
        /// </summary>
        public abstract bool Writeable { get; }

        /// <summary>
        /// True if this column can be read from. That is,
        /// whether calling the Read method will return a valid value.
        /// </summary>
        public abstract bool Readable { get; }

        /// <summary>
        /// Attempts to write a given value info a given target object.
        /// </summary>
        /// <param name="target">target object</param>
        /// <param name="value">value to write</param>
        public abstract void Write(object target, object value);

        /// <summary>
        /// Attempts to read a value from a given source object.
        /// </summary>
        /// <param name="source">source object</param>
        /// <returns>value of this column from the source object</returns>
        public abstract object Read(object source);
    }
}
